package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.article.dto.ArticleCache;
import com.heima.article.dto.ArticleStreamMessage;
import com.heima.article.entity.ApArticle;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IHotArticleService;
import com.heima.common.util.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class HotArticleServiceImpl implements IHotArticleService {


    @Autowired
    IApArticleService articleService;

    @Autowired
    StringRedisTemplate redisTemplate;
    /*
        计算热点文章
     */
    @Override
    public void countHot() {
        System.out.println("开始执行计算热点文章");
        //查询从每天0点0分0秒往前推5天的所有文章
        Date now = new Date();
        Date to = new Date(now.getYear(), now.getMonth(), now.getDate());
        Date start = new Date(to.getTime() - 5 * 24 * 60 * 60 * 1000);

        //查询符合时间的文章
        LambdaQueryWrapper<ApArticle> querry = new LambdaQueryWrapper();
        querry.lt(ApArticle::getPublishTime,to);
        querry.gt(ApArticle::getPublishTime,start);
        //过滤删除和下架的文章
        querry.eq(ApArticle::getIsDelete,false);
        querry.eq(ApArticle::getIsDown,false);
        List<ApArticle> articleList = articleService.list(querry);
        //计算文章分值
        for (ApArticle apArticle : articleList) {
            double score = countScore(apArticle);
            //为推荐和每个频道的首页缓存文章和其分值
            //需要按分值排序   redis的zset数据结构
            //需要确定zest的value怎么设置
            ArticleCache articleCache = new ArticleCache();
            BeanUtils.copyProperties(apArticle,articleCache);
            String key = "hot_article_first_page_0";
            String value = JSON.toJSONString(articleCache);
            //为首页缓存文章和分值
            redisTemplate.opsForZSet().add(key,value,score);

            //为每个频道缓存文章和分值
           String keyChannel =  "hot_article_first_page_" + apArticle.getChannelId();
           redisTemplate.opsForZSet().add(keyChannel,value,score);
            //设置过期时间
            redisTemplate.expire(key,23 * 60 + 59, TimeUnit.MINUTES);
            redisTemplate.expire(keyChannel,23 * 60 + 59, TimeUnit.MINUTES);
        }
    }

    /*
        修改文章分值
     */
    @Override
    public void update(ArticleStreamMessage message) {
        //根据id查询文章
        ApArticle article = articleService.getById(message.getArticleId());
        //一段时间内聚合的结果
        //计算本次聚合的分值
        double scorePlus = computerScore(message);
        //更新redis中的分值
        //判断redis中是否有这篇文章
        String key = "hot_article_" + article.getChannelId();
        ArticleCache articleCache = new ArticleCache();
        BeanUtils.copyProperties(article,articleCache);
        String value = JSON.toJSONString(articleCache);
        Double score = redisTemplate.opsForZSet().score(key, value);
        if (score == null){
            //不存在   先计算历史分值 再加上增量分值  重新写入
            double historyScore = countScore(article);
            double newScore = historyScore + scorePlus;
            redisTemplate.opsForZSet().add(key,value,newScore);
            redisTemplate.opsForZSet().add("hot_article_0",value,newScore);
            //添加过期时间
            redisTemplate.expire(key,23*60+58,TimeUnit.MINUTES);
            redisTemplate.expire("hot_article_0",23 *60+58,TimeUnit.MINUTES);
        }else {
            //如果存在 则直接把新增量加到原有的分值上
            redisTemplate.opsForZSet().incrementScore(key,value,scorePlus);
            redisTemplate.opsForZSet().incrementScore("hot_article_0",value,scorePlus);
        }
        //更新文章表的数据
        LambdaUpdateWrapper<ApArticle> update = new LambdaUpdateWrapper();
        update.eq(ApArticle::getId,message.getArticleId());
        update.setSql("views = views + " + message.getView());
        update.setSql("likes = likes + " + message.getLike());
        update.setSql("comment = comment + " + message.getComment());
        update.setSql("collection = collection + " + message.getCollect());
        articleService.update(update);

    }

    private double computerScore(ArticleStreamMessage message) {
        double score = 0;
        score += message.getView() * 1 *3;
        score += message.getLike() * 3 *3;
        score += message.getComment() * 5 * 3;
        score += message.getCollect() * 8 * 3;
        return score;
    }

    /*
        计算热点文章权重
     */
    private double countScore(ApArticle apArticle) {
        double score = 0;
        // 阅读 1'  点赞 3'  评论 5'   收藏 8'
        if (apArticle.getViews() != null){
            score += apArticle.getViews() * 1;
        }
        if (apArticle.getLikes() != null){
            score += apArticle.getLikes() * 3;
        }
        if (apArticle.getComment() != null){
            score += apArticle.getComment() * 5;
        }
        if (apArticle.getCollection() != null){
            score += apArticle.getCollection() * 8;
        }
        return score;
    }
}
